/**
 * Copyright 2018-2020 stylefeng & fengshuonan (https://gitee.com/stylefeng)
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.jetpiece.cloud.system.dp.app.core.aop;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.jetpiece.cloud.core.util.HttpContext;
import cn.jetpiece.cloud.model.exception.ServiceException;
import cn.jetpiece.cloud.system.dp.app.consts.CommonConstant;
import cn.jetpiece.cloud.system.dp.app.core.aop.annotion.Permission;
import cn.jetpiece.cloud.system.dp.app.enums.DataSourceEnum;
import cn.jetpiece.cloud.system.dp.app.enums.PermCheckEnum;
import cn.jetpiece.cloud.system.dp.app.modular.biz.entity.DpTApi;
import cn.jetpiece.cloud.system.dp.app.modular.biz.entity.DpTApp;
import cn.jetpiece.cloud.system.dp.app.modular.biz.entity.DpTProject;
import cn.jetpiece.cloud.system.dp.app.modular.biz.entity.DpTScopeData;
import cn.jetpiece.cloud.system.dp.app.modular.biz.service.IDpTApiService;
import cn.jetpiece.cloud.system.dp.app.modular.biz.service.IDpTAppService;
import cn.jetpiece.cloud.system.dp.app.modular.biz.service.IDpTProjectService;
import cn.jetpiece.cloud.system.dp.app.modular.biz.service.IDpTScopeDataService;
import cn.jetpiece.cloud.system.dp.app.utils.HttpReqUtils;
import cn.jetpiece.cloud.system.dp.app.utils.JwtUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 *
 */
@Aspect
@Component
@Order(200)
public class PermissionAop {

    @Autowired
    private IDpTAppService dpTAppService;

    @Autowired
    private IDpTApiService dpTApiService;

    @Autowired
    private IDpTScopeDataService dpTScopeDataService;

    @Autowired
    private IDpTProjectService dpTProjectService;

    @Pointcut(value = "@annotation(cn.jetpiece.cloud.system.dp.app.core.aop.annotion.Permission)")
    private void cutPermission() {

    }

    @Around("cutPermission()")
    public Object doPermission(ProceedingJoinPoint point) throws Throwable {
        try {
            MethodSignature ms = (MethodSignature) point.getSignature();
            Method method = ms.getMethod();
            Permission permission = method.getAnnotation(Permission.class);
            if (ObjectUtil.isNotNull(permission)) {
                String token = HttpContext.getRequest().getHeader(CommonConstant.AUTHORIZATION);
                if (StringUtils.isBlank(token)) {
                    throw new ServiceException(501, "未认证授权访问");
                }
                String appKey = JwtUtil.getUsername(token);
                DpTApp app = dpTAppService.getByAppKey(appKey);
                if (ObjectUtil.isNull(app)) {
                    throw new ServiceException(502, "汇接信息缺失");
                }
                boolean isVerify = JwtUtil.verify(token, appKey, app.getAppSecret());
                if (!isVerify) {
                    throw new ServiceException(503, "token认证失效");
                }
                String servletPath = HttpReqUtils.subServletPath();
                DpTApi dpTApi = dpTApiService.getByPath(appKey, servletPath);
                if (ObjectUtil.isNull(dpTApi)) {
                    throw new ServiceException(504, "接口授权访问缺失");
                }
                Integer apiId = dpTApi.getId();
                DpTScopeData scopeData = dpTScopeDataService.getByAppKey(appKey);
                if (ObjectUtil.isNull(scopeData)) {
                    throw new ServiceException(505, "数据权限访问缺失");
                }
                if (StringUtils.isBlank(scopeData.getApiValue()) || !scopeData.getApiValue().contains(apiId + ",")) {
                    throw new ServiceException(504, "接口未授权访问,apiId：" + apiId);
                }
                if (PermCheckEnum.N.getValue().equals(dpTApi.getProjPermCheck())) {
                    return point.proceed();
                }
                Object apiObj = point.getArgs()[0];
                Field apiField = ReflectionUtils.findField(apiObj.getClass(), "params");
                if (ObjectUtil.isNotNull(apiField)) {
                    apiField.setAccessible(true);
                } else {
                    throw new ServiceException(506, "未找到参数对象的params属性");
                }
                Object paramsObj = ReflectionUtils.getField(apiField, apiObj);
                JSONObject paramsJson = JSONUtil.parseObj(paramsObj);
                String builderLicenseNum = paramsJson.getStr("builderLicenseId");
                String projectId = paramsJson.getStr("projectId");
                if (StringUtils.isBlank(builderLicenseNum) && StringUtils.isBlank(projectId)) {
                    throw new ServiceException(507, "项目未授权访问");
                }
                if (StringUtils.isBlank(projectId)) {
                    DpTProject project = dpTProjectService.getByLicenceNum(builderLicenseNum);
                    if (ObjectUtil.isNotNull(project)) {
                        projectId = String.valueOf(project.getProjectId());
                    }
                } else {
                    DpTProject project = dpTProjectService.findBySourceId(Integer.valueOf(projectId), DataSourceEnum.OMS.getCode());
                    if (ObjectUtil.isNotNull(project)) {
                        projectId = String.valueOf(project.getProjectId());
                    }
                }
                if (StringUtils.isBlank(scopeData.getProjectValue()) || !scopeData.getProjectValue().contains(projectId + ",")) {
                    throw new ServiceException(507, "项目未授权访问,projectId：" + projectId);
                }
            }
        } catch (Throwable te) {
            if (te instanceof ServiceException) {
                throw te;
            } else {
                throw new ServiceException(509, te.getMessage());
            }
        }
        return point.proceed();
    }

}
